package com.ruoyi.match.match.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.match.dto.OddsDto;
import com.ruoyi.match.enums.JqEnum;
import com.ruoyi.match.enums.ScoreEnum;
import com.ruoyi.match.match.domain.HistoryMatchOddsChange;
import com.ruoyi.match.match.domain.Match;
import com.ruoyi.match.match.domain.RealTimeMatch;
import com.ruoyi.match.match.dto.JqPriceDto;
import com.ruoyi.match.match.dto.SortDto;
import com.ruoyi.match.match.mapper.HistoryMatchOddsChangeMapper;
import com.ruoyi.match.match.mapper.MatchMapper;
import com.ruoyi.match.match.service.CommonService;
import com.ruoyi.match.match.vo.*;
import com.ruoyi.match.test.dto.JqCountDto;
import com.ruoyi.match.utils.OddsRangeUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author sjz
 * @Date 2023/11/21 13:24
 * @Desc
 */

@Slf4j
@RequiredArgsConstructor
@Service
public class CommonServiceImpl implements CommonService {

    private final HistoryMatchOddsChangeMapper matchOddsChangeMapper;
    private final MatchMapper matchMapper;

    @Override
    public void oddsChangeList(MatchInfoVO matchInfoVO) {
        List<HistoryMatchOddsChange> historyMatchOddsChanges = matchOddsChangeMapper.selectList(Wrappers.<HistoryMatchOddsChange>lambdaQuery()
            .eq(HistoryMatchOddsChange::getMatchFlag, matchInfoVO.getBaseInfo().getMatchFlag()));
        Map<Integer, List<HistoryMatchOddsChange>> changeMap = historyMatchOddsChanges.stream().collect(Collectors.groupingBy(HistoryMatchOddsChange::getType));
        // 竞彩赔率变化列表
        List<HistoryMatchOddsChange> jcChangeList = changeMap.containsKey(1) ? changeMap.get(1) : Lists.newArrayList();
        oddsHandler(1,jcChangeList,matchInfoVO);
        // 威廉赔率变化列表
        List<HistoryMatchOddsChange> vlChangeList = changeMap.containsKey(2) ? changeMap.get(2) : Lists.newArrayList();
        oddsHandler(2,vlChangeList,matchInfoVO);
        // 立博赔率变化列表
        List<HistoryMatchOddsChange> lbChangeList = changeMap.containsKey(3) ? changeMap.get(3) : Lists.newArrayList();
        oddsHandler(3,lbChangeList,matchInfoVO);
    }

    @Override
    public String getMatchJqSortList(Match match) {
        String matchScore = match.getMatchScore();
        int num = getJqResultByScore(matchScore);
        List<SortDto> sortDtoList = Lists.newArrayList();

        for (JqEnum value : JqEnum.values()) {
            switch (value){
                case JQ_0:
                    sortDtoList.add(getJqSortDto(value,match.getJq0(),num == value.getIndex()));
                    break;
                case JQ_1:
                    sortDtoList.add(getJqSortDto(value,match.getJq1(),num == value.getIndex()));
                    break;
                case JQ_2:
                    sortDtoList.add(getJqSortDto(value,match.getJq2(),num == value.getIndex()));
                    break;
                case JQ_3:
                    sortDtoList.add(getJqSortDto(value,match.getJq3(),num == value.getIndex()));
                    break;
                case JQ_4:
                    sortDtoList.add(getJqSortDto(value,match.getJq4(),num == value.getIndex()));
                    break;
                case JQ_5:
                    sortDtoList.add(getJqSortDto(value,match.getJq5(),num == value.getIndex()));
                    break;
                default:
                    break;
            }
        }
        return sortDtoList.stream().sorted(Comparator.comparing(SortDto::getValue)).map(SortDto::getName).collect(Collectors.joining("->"));
    }


    private SortDto getJqSortDto(JqEnum value, BigDecimal jq, Boolean result) {
        SortDto dto = new SortDto();
        dto.setName(value.getCode());
        dto.setValue(jq);
        dto.setResult(result);
        return dto;
    }

    @Override
    public String getRealTimeJqSortList(RealTimeMatch match) {
        List<SortDto> sortDtoList = Lists.newArrayList();

        for (JqEnum value : JqEnum.values()) {
            switch (value){
                case JQ_0:
                    sortDtoList.add(getJqSortDto(value,match.getJq0(),false));
                    break;
                case JQ_1:
                    sortDtoList.add(getJqSortDto(value,match.getJq1(),false));
                    break;
                case JQ_2:
                    sortDtoList.add(getJqSortDto(value,match.getJq2(),false));
                    break;
                case JQ_3:
                    sortDtoList.add(getJqSortDto(value,match.getJq3(),false));
                    break;
                case JQ_4:
                    sortDtoList.add(getJqSortDto(value,match.getJq4(),false));
                    break;
                case JQ_5:
                    sortDtoList.add(getJqSortDto(value,match.getJq5(),false));
                    break;
                default:
                    break;
            }
        }
        return sortDtoList.stream().sorted(Comparator.comparing(SortDto::getValue)).map(SortDto::getName).collect(Collectors.joining("->"));
    }

    @Override
    public void distributedComputing(MatchInfoVO matchInfoVO) {
        String currentJqSort = matchInfoVO.getBaseInfo().getCurrentJqSort();
        List<Match> matches = Lists.newArrayList();
        List<MatchOdds> jcOdds = matchInfoVO.getBaseInfo().getJcOdds();
        String rq = matchInfoVO.getBaseInfo().getRq();
        if(CollUtil.isNotEmpty(jcOdds)){
            // 初赔
            matches = getInitMatchList(jcOdds,currentJqSort,1);
            // 比分 详细分布
            List<MatchDistributionVO> currentMatchRangeList = matchInfoVO.getCurrentMatchRangeList();
//            for (MatchDistributionVO matchDistributionVO : currentMatchRangeList) {
//                if(CollUtil.isNotEmpty(matchDistributionVO.getCsList())){
//                    List<MatchDistributionNumVO> csList = matchDistributionVO.getCsList();
//                    for (MatchDistributionNumVO vo : csList) {
//                        BigDecimal price = vo.getPrice();
//                        vo.setDesc(getScoreDesc(vo.getLabel(),price,matches,matchInfoVO.getBaseInfo().getRq()));
//                    }
//                }
//            }
            CompanyVO jcInit = getCompanyVo(matches,rq);
            matchInfoVO.setJcInit(jcInit);
            jqPriceHandler(matches,matchInfoVO);
            // 初培和终赔
            matches = getMatchList(jcOdds,currentJqSort,1);
            CompanyVO jcFinal = getCompanyVo(matches,rq);
            matchInfoVO.setJcFinal(jcFinal);
        }

        List<MatchOdds> vlOdds = matchInfoVO.getBaseInfo().getVlOdds();
        if(CollUtil.isNotEmpty(vlOdds)){
            // 初赔
            matches = getInitMatchList(vlOdds,currentJqSort,2);
            CompanyVO vlInit = getCompanyVo(matches,rq);
            matchInfoVO.setVlInit(vlInit);
            // 初培和终赔
            matches = getMatchList(vlOdds,currentJqSort,2);
            CompanyVO vlFinal = getCompanyVo(matches,rq);
            matchInfoVO.setVlFinal(vlFinal);
        }

        List<MatchOdds> lbOdds = matchInfoVO.getBaseInfo().getLbOdds();
        if(CollUtil.isNotEmpty(lbOdds)){
            // 初赔
            matches = getInitMatchList(lbOdds,currentJqSort,3);
            CompanyVO lbInit = getCompanyVo(matches,rq);
            matchInfoVO.setLbInit(lbInit);
            // 初培和终赔
            matches = getMatchList(lbOdds,currentJqSort,3);
            CompanyVO lbFinal = getCompanyVo(matches,rq);
            matchInfoVO.setLbFinal(lbFinal);
        }
    }

    private void jqPriceHandler(List<Match> matches,MatchInfoVO matchInfoVO) {
        Map<BigDecimal, List<Match>> jq0Map = matches.stream().collect(Collectors.groupingBy(Match::getJq0));
        List<JqPriceDto> jq0List = Lists.newArrayList();
        jq0Map.forEach((k,v) ->{
            JqPriceDto dto = new JqPriceDto();
            dto.setPrice(k);
            dto.setNum(v.size());
            jq0List.add(dto);
        });
        JqPriceDto avgDto = new JqPriceDto();
        avgDto.setPrice(avgHandler(jq0List));
        avgDto.setNum(99);
        jq0List.add(avgDto);
        List<JqPriceDto> collect = jq0List.stream().sorted(Comparator.comparing(JqPriceDto::getPrice).reversed()).collect(Collectors.toList());
        matchInfoVO.setJq0List(collect);
        matchInfoVO.setJq0Avg(avgDto.getPrice());


        Map<BigDecimal, List<Match>> jq1Map = matches.stream().collect(Collectors.groupingBy(Match::getJq1));
        List<JqPriceDto> jq1List = Lists.newArrayList();
        jq1Map.forEach((k,v) ->{
            JqPriceDto dto = new JqPriceDto();
            dto.setPrice(k);
            dto.setNum(v.size());
            jq1List.add(dto);
        });
        avgDto = new JqPriceDto();
        avgDto.setPrice(avgHandler(jq1List));
        avgDto.setNum(99);
        jq1List.add(avgDto);
        collect = jq1List.stream().sorted(Comparator.comparing(JqPriceDto::getPrice).reversed()).collect(Collectors.toList());
        matchInfoVO.setJq1List(collect);
        matchInfoVO.setJq1Avg(avgDto.getPrice());

        Map<BigDecimal, List<Match>> jq2Map = matches.stream().collect(Collectors.groupingBy(Match::getJq2));
        List<JqPriceDto> jq2List = Lists.newArrayList();
        jq2Map.forEach((k,v) ->{
            JqPriceDto dto = new JqPriceDto();
            dto.setPrice(k);
            dto.setNum(v.size());
            jq2List.add(dto);
        });
        avgDto = new JqPriceDto();
        avgDto.setPrice(avgHandler(jq2List));
        avgDto.setNum(99);
        jq2List.add(avgDto);
        collect = jq2List.stream().sorted(Comparator.comparing(JqPriceDto::getPrice).reversed()).collect(Collectors.toList());
        matchInfoVO.setJq2List(collect);
        matchInfoVO.setJq2Avg(avgDto.getPrice());

        Map<BigDecimal, List<Match>> jq3Map = matches.stream().collect(Collectors.groupingBy(Match::getJq3));
        List<JqPriceDto> jq3List = Lists.newArrayList();
        jq3Map.forEach((k,v) ->{
            JqPriceDto dto = new JqPriceDto();
            dto.setPrice(k);
            dto.setNum(v.size());
            jq3List.add(dto);
        });
        avgDto = new JqPriceDto();
        avgDto.setPrice(avgHandler(jq3List));
        avgDto.setNum(99);
        jq3List.add(avgDto);
        collect = jq3List.stream().sorted(Comparator.comparing(JqPriceDto::getPrice).reversed()).collect(Collectors.toList());
        matchInfoVO.setJq3List(collect);
        matchInfoVO.setJq3Avg(avgDto.getPrice());

        Map<BigDecimal, List<Match>> jq4Map = matches.stream().collect(Collectors.groupingBy(Match::getJq4));
        List<JqPriceDto> jq4List = Lists.newArrayList();
        jq4Map.forEach((k,v) ->{
            JqPriceDto dto = new JqPriceDto();
            dto.setPrice(k);
            dto.setNum(v.size());
            jq4List.add(dto);
        });
        avgDto = new JqPriceDto();
        avgDto.setPrice(avgHandler(jq4List));
        avgDto.setNum(99);
        jq4List.add(avgDto);
        collect = jq4List.stream().sorted(Comparator.comparing(JqPriceDto::getPrice).reversed()).collect(Collectors.toList());
        matchInfoVO.setJq4List(collect);
        matchInfoVO.setJq4Avg(avgDto.getPrice());

        Map<BigDecimal, List<Match>> jq5Map = matches.stream().collect(Collectors.groupingBy(Match::getJq5));
        List<JqPriceDto> jq5List = Lists.newArrayList();
        jq5Map.forEach((k,v) ->{
            JqPriceDto dto = new JqPriceDto();
            dto.setPrice(k);
            dto.setNum(v.size());
            jq5List.add(dto);
        });
        avgDto = new JqPriceDto();
        avgDto.setPrice(avgHandler(jq5List));
        avgDto.setNum(99);
        jq5List.add(avgDto);
        collect = jq5List.stream().sorted(Comparator.comparing(JqPriceDto::getPrice).reversed()).collect(Collectors.toList());
        matchInfoVO.setJq5List(collect);
        matchInfoVO.setJq5Avg(avgDto.getPrice());

        Map<BigDecimal, List<Match>> jq6Map = matches.stream().collect(Collectors.groupingBy(Match::getJq6));
        List<JqPriceDto> jq6List = Lists.newArrayList();
        jq6Map.forEach((k,v) ->{
            JqPriceDto dto = new JqPriceDto();
            dto.setPrice(k);
            dto.setNum(v.size());
            jq6List.add(dto);
        });
        avgDto = new JqPriceDto();
        avgDto.setPrice(avgHandler(jq6List));
        avgDto.setNum(99);
        jq6List.add(avgDto);
        collect = jq6List.stream().sorted(Comparator.comparing(JqPriceDto::getPrice).reversed()).collect(Collectors.toList());
        matchInfoVO.setJq6List(collect);
        matchInfoVO.setJq6Avg(avgDto.getPrice());


        Map<BigDecimal, List<Match>> jqGt6Map = matches.stream().collect(Collectors.groupingBy(Match::getJqGt6));
        List<JqPriceDto> jqGt6t = Lists.newArrayList();
        jqGt6Map.forEach((k,v) ->{
            JqPriceDto dto = new JqPriceDto();
            dto.setPrice(k);
            dto.setNum(v.size());
            jqGt6t.add(dto);
        });
        avgDto = new JqPriceDto();
        avgDto.setPrice(avgHandler(jqGt6t));
        avgDto.setNum(99);
        jqGt6t.add(avgDto);
        collect = jqGt6t.stream().sorted(Comparator.comparing(JqPriceDto::getPrice).reversed()).collect(Collectors.toList());
        matchInfoVO.setJqGt6List(collect);
        matchInfoVO.setJq7Avg(avgDto.getPrice());
    }

    private BigDecimal avgHandler(List<JqPriceDto> collect) {
        if(CollUtil.isNotEmpty(collect)){
            BigDecimal all = collect.stream().map(m-> m.getPrice().multiply(new BigDecimal(m.getNum()))).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal num = collect.stream().map(m -> new BigDecimal(m.getNum())).reduce(BigDecimal.ZERO, BigDecimal::add);
            return all.divide(num,2,RoundingMode.FLOOR);
        }
        return BigDecimal.ZERO;
    }

    private String getScoreDesc(String type, BigDecimal price, List<Match> matches,String rq) {
        ScoreEnum scoreByMatchScoreResult = ScoreEnum.getScoreByMatchScoreResult(type);
        StringJoiner stringJoiner = new StringJoiner("|");
        if(scoreByMatchScoreResult != null){
            List<Match> collect = matches.stream().filter(f -> f.getRq().equals(rq)).collect(Collectors.toList());

            Map<BigDecimal, List<Match>> priceMap = new HashMap<>();
            switch (scoreByMatchScoreResult){
                case CS_0_1:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs01));
                    break;
                case CS_0_2:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs02));
                    break;
                case CS_0_3:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs03));
                    break;
                case CS_0_4:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs04));
                    break;
                case CS_0_5:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs05));
                    break;
                case CS_1_0:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs10));
                    break;
                case CS_1_2:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs12));
                    break;
                case CS_1_3:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs13));
                    break;
                case CS_1_4:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs14));
                    break;
                case CS_1_5:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs15));
                    break;
                case CS_2_0:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs20));
                    break;
                case CS_2_1:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs21));
                    break;
                case CS_2_3:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs23));
                    break;
                case CS_2_4:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs24));
                    break;
                case CS_2_5:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs25));
                    break;
                case CS_3_0:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs30));
                    break;
                case CS_3_1:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs31));
                    break;
                case CS_3_2:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs32));
                    break;
                case CS_4_0:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs40));
                    break;
                case CS_4_1:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs41));
                    break;
                case CS_4_2:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs42));
                    break;
                case CS_5_0:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs50));
                    break;
                case CS_5_1:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs51));
                    break;
                case CS_5_2:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getCs52));
                    break;
                case LEVEL_0_0:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getLevel00));
                    break;
                case LEVEL_1_1:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getLevel11));
                    break;
                case LEVEL_2_2:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getLevel22));
                    break;
                case LEVEL_3_3:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getLevel33));
                    break;
                case LEVEL_OTHER:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getLostOther));
                    break;
                case WIN_OTHER:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getWinOther));
                    break;
                case LOST_OTHER:
                    priceMap = collect.stream().collect(Collectors.groupingBy(Match::getLostOther));
                    break;
            }


            int size = priceMap.size();
            if(size > 0){
                stringJoiner.add(String.valueOf(size));
                int index = 1;
                Set<BigDecimal> bigDecimals = priceMap.keySet();
                List<BigDecimal> sortList = Lists.newArrayList();
                sortList.addAll(bigDecimals);
                if(!sortList.contains(price)){
                    sortList.add(price);
                }
                sortList = sortList.stream().sorted().collect(Collectors.toList());

                for (BigDecimal bigDecimal : sortList) {
                    if(price.compareTo(bigDecimal) == 0){
                        stringJoiner.add(String.valueOf(index));
                        break;
                    }
                    index++;
                }
            }
        }
        return stringJoiner.toString();
    }

    @Override
    public void getOddRiskAssessment(MatchInfoVO matchInfoVO) {
        List<MatchOdds> jcOdds = matchInfoVO.getBaseInfo().getJcOdds();
        List<MatchOdds> vlOdds = matchInfoVO.getBaseInfo().getVlOdds();
        List<MatchOdds> lbOdds = matchInfoVO.getBaseInfo().getLbOdds();

        Optional<MatchOdds> jcInitOdd = jcOdds.stream().filter(f -> f.getInitFlag().equals(Boolean.TRUE)).findFirst();
        Optional<MatchOdds> vlInitOdd = vlOdds.stream().filter(f -> f.getInitFlag().equals(Boolean.TRUE)).findFirst();
        Optional<MatchOdds> lbInitOdd = lbOdds.stream().filter(f -> f.getInitFlag().equals(Boolean.TRUE)).findFirst();
        Optional<MatchOdds> jcFinalOdd = jcOdds.stream().filter(f -> f.getInitFlag().equals(Boolean.FALSE)).findFirst();
        Optional<MatchOdds> vlFinalOdd = vlOdds.stream().filter(f -> f.getInitFlag().equals(Boolean.FALSE)).findFirst();
        Optional<MatchOdds> lbFinalOdd = lbOdds.stream().filter(f -> f.getInitFlag().equals(Boolean.FALSE)).findFirst();

        List<OddRiskAssessment> riskAssessments = Lists.newArrayList();
        OddRiskAssessment initRisk = getRiskAssessment(jcInitOdd,vlInitOdd,lbInitOdd,Boolean.TRUE);
        OddRiskAssessment finalRisk = getRiskAssessment(jcFinalOdd,vlFinalOdd,lbFinalOdd,Boolean.FALSE);

        riskAssessments.add(initRisk);
        riskAssessments.add(finalRisk);

        matchInfoVO.setRiskAssessments(riskAssessments);
    }

    @Override
    public void letTheBallCalculate(MatchInfoVO matchInfoVO) {
        List<JqCountDto> rqInitJcList = matchInfoVO.getJcInit().getRqList();
        List<JqCountDto> rqInitVlList = matchInfoVO.getVlInit().getRqList();
        List<JqCountDto> rqInitLbList = matchInfoVO.getLbInit().getRqList();
        List<JqCountDto> rqFinalJcList = matchInfoVO.getJcFinal().getRqList();
        List<JqCountDto> rqFinalVlList = matchInfoVO.getVlFinal().getRqList();
        List<JqCountDto> rqFinalLbList = matchInfoVO.getLbFinal().getRqList();
        RqNumVO rqNumVO = new RqNumVO();
        if(CollUtil.isNotEmpty(rqInitJcList)){
            rqNumHandler(rqNumVO,rqInitJcList);
        }
        if(CollUtil.isNotEmpty(rqInitVlList)){
            rqNumHandler(rqNumVO,rqInitVlList);
        }
        if(CollUtil.isNotEmpty(rqInitLbList)){
            rqNumHandler(rqNumVO,rqInitLbList);
        }
        matchInfoVO.setRqInitNumVO(rqNumVO);

        rqNumVO = new RqNumVO();
        if(CollUtil.isNotEmpty(rqFinalJcList)){
            rqNumHandler(rqNumVO,rqFinalJcList);
        }
        if(CollUtil.isNotEmpty(rqFinalVlList)){
            rqNumHandler(rqNumVO,rqFinalVlList);
        }
        if(CollUtil.isNotEmpty(rqFinalLbList)){
            rqNumHandler(rqNumVO,rqFinalLbList);
        }
        matchInfoVO.setRqFinalNumVO(rqNumVO);

        rqNumVO = new RqNumVO();
        rqNumVO.setMainNum(matchInfoVO.getRqInitNumVO().getMainNum()+matchInfoVO.getRqFinalNumVO().getMainNum());
        rqNumVO.setLevelNum(matchInfoVO.getRqInitNumVO().getLevelNum()+matchInfoVO.getRqFinalNumVO().getLevelNum());
        rqNumVO.setGustNum(matchInfoVO.getRqInitNumVO().getGustNum()+matchInfoVO.getRqFinalNumVO().getGustNum());
        matchInfoVO.setRqAllNumVO(rqNumVO);
    }

    @Override
    public void jqDistributedComputing(MatchInfoVO matchInfoVO) {
        List<JqCountDto> jqInitJcList = matchInfoVO.getJcInit().getJqList();
        List<JqCountDto> jqInitVlList = matchInfoVO.getVlInit().getJqList();
        List<JqCountDto> jqInitLbList = matchInfoVO.getLbInit().getJqList();
        List<JqCountDto> jqFinalJcList = matchInfoVO.getJcFinal().getJqList();
        List<JqCountDto> jqFinalVlList = matchInfoVO.getVlFinal().getJqList();
        List<JqCountDto> jqFinalLbList = matchInfoVO.getLbFinal().getJqList();

        List<JqNumVO> initJqNumList = Lists.newArrayList();
        List<JqNumVO> finalJqNumList = Lists.newArrayList();
        List<JqNumVO> allJqNumList = Lists.newArrayList();
        for (int i = 0; i < 6; i++) {
            if(jqInitJcList.size() > i){
                jcDtoHandler(jqInitJcList.get(i),initJqNumList);
                jcDtoHandler(jqInitJcList.get(i),allJqNumList);
            }

            if(jqInitVlList.size() >i){
                jcDtoHandler(jqInitVlList.get(i),initJqNumList);
                jcDtoHandler(jqInitVlList.get(i),allJqNumList);
            }

            if(jqInitLbList.size() >i){
                jcDtoHandler(jqInitLbList.get(i),initJqNumList);
                jcDtoHandler(jqInitLbList.get(i),allJqNumList);
            }


            if(jqFinalJcList.size() >i){
                jcDtoHandler(jqFinalJcList.get(i),finalJqNumList);
                jcDtoHandler(jqFinalJcList.get(i),allJqNumList);
            }

            if(jqFinalVlList.size() >i){
                jcDtoHandler(jqFinalVlList.get(i),finalJqNumList);
                jcDtoHandler(jqFinalVlList.get(i),allJqNumList);
            }
            if(jqFinalLbList.size() >i){
                jcDtoHandler(jqFinalLbList.get(i),finalJqNumList);
                jcDtoHandler(jqFinalLbList.get(i),allJqNumList);
            }
        }

        matchInfoVO.setInitJqNumList(initJqNumList);
        matchInfoVO.setFinalJqNumList(finalJqNumList);
        matchInfoVO.setAllJqNumList(allJqNumList);
    }

    private void jcDtoHandler(JqCountDto dto, List<JqNumVO> jqNumList) {
        String desc = dto.getDesc();
        Integer num = dto.getNum();
        Optional<JqNumVO> first = jqNumList.stream().filter(f -> f.getDesc().equals(desc)).findFirst();
        if (first.isPresent()) {
            JqNumVO jqNumVO = first.get();
            jqNumVO.setNum(jqNumVO.getNum()+num);
        }else {
            JqNumVO jqNumVO = new JqNumVO();
            jqNumVO.setDesc(desc);
            jqNumVO.setNum(num);
            jqNumList.add(jqNumVO);
        }
    }

    @Override
    public void scoreDistributedComputing(MatchInfoVO matchInfoVO) {
        List<JqCountDto> scoreInitJcList = matchInfoVO.getJcInit().getScoreList();
        List<JqCountDto> scoreInitVlList = matchInfoVO.getVlInit().getScoreList();
        List<JqCountDto> scoreInitLbList = matchInfoVO.getLbInit().getScoreList();
        List<JqCountDto> scoreFinalJcList = matchInfoVO.getJcFinal().getScoreList();
        List<JqCountDto> scoreFinalVlList = matchInfoVO.getVlFinal().getScoreList();
        List<JqCountDto> scoreFinalLbList = matchInfoVO.getLbFinal().getScoreList();
        RqNumVO rqNumVO = new RqNumVO();
        if(CollUtil.isNotEmpty(scoreInitJcList)){
            scoreNumHandler(rqNumVO,scoreInitJcList);
        }
        if(CollUtil.isNotEmpty(scoreInitVlList)){
            scoreNumHandler(rqNumVO,scoreInitVlList);
        }
        if(CollUtil.isNotEmpty(scoreInitLbList)){
            scoreNumHandler(rqNumVO,scoreInitLbList);
        }
        matchInfoVO.setScoreInitNumVO(rqNumVO);

        rqNumVO = new RqNumVO();
        if(CollUtil.isNotEmpty(scoreFinalJcList)){
            scoreNumHandler(rqNumVO,scoreFinalJcList);
        }
        if(CollUtil.isNotEmpty(scoreFinalVlList)){
            scoreNumHandler(rqNumVO,scoreFinalVlList);
        }
        if(CollUtil.isNotEmpty(scoreFinalLbList)){
            scoreNumHandler(rqNumVO,scoreFinalLbList);
        }
        matchInfoVO.setScoreFinalNumVO(rqNumVO);

        rqNumVO = new RqNumVO();
        rqNumVO.setMainNum(matchInfoVO.getScoreInitNumVO().getMainNum()+matchInfoVO.getScoreFinalNumVO().getMainNum());
        rqNumVO.setLevelNum(matchInfoVO.getScoreInitNumVO().getLevelNum()+matchInfoVO.getScoreFinalNumVO().getLevelNum());
        rqNumVO.setGustNum(matchInfoVO.getScoreInitNumVO().getGustNum()+matchInfoVO.getScoreFinalNumVO().getGustNum());
        matchInfoVO.setScoreAllNumVO(rqNumVO);
    }


    private void scoreNumHandler(RqNumVO rqNumVO, List<JqCountDto> scoreInitJcList) {
        for (int i = 0; i < scoreInitJcList.size(); i++) {
            JqCountDto dto = scoreInitJcList.get(i);
            String desc = dto.getDesc();
            String[] split = desc.split(":");
            BigDecimal mainJq = new BigDecimal(split[0]);
            BigDecimal gustJq = new BigDecimal(split[1]);
            if(mainJq.compareTo(gustJq) == 0){
                rqNumVO.setLevelNum(rqNumVO.getMainNum()+dto.getNum());
            }else if(mainJq.compareTo(gustJq) > 0){
                rqNumVO.setMainNum(rqNumVO.getMainNum()+dto.getNum());
            }else {
                rqNumVO.setGustNum(rqNumVO.getMainNum()+dto.getNum());
            }
        }
    }

    private void rqNumHandler(RqNumVO rqNumVO, List<JqCountDto> rqInitLbList) {
        Map<String, List<JqCountDto>> collect = rqInitLbList.stream().collect(Collectors.groupingBy(JqCountDto::getDesc));
        if(collect.containsKey("主")){
            int sum = collect.get("主").stream().mapToInt(JqCountDto::getNum).sum();
            rqNumVO.setMainNum(rqNumVO.getMainNum()+sum);
        }
        if(collect.containsKey("平")){
            int sum = collect.get("平").stream().mapToInt(JqCountDto::getNum).sum();
            rqNumVO.setLevelNum(rqNumVO.getLevelNum()+sum);
        }
        if(collect.containsKey("客")){
            int sum = collect.get("客").stream().mapToInt(JqCountDto::getNum).sum();
            rqNumVO.setGustNum(rqNumVO.getGustNum()+sum);
        }
    }

    private OddRiskAssessment getRiskAssessment(Optional<MatchOdds> jcOdd, Optional<MatchOdds> vlOdd, Optional<MatchOdds> lbOdd,Boolean initFlag) {
        OddRiskAssessment riskAssessment = new OddRiskAssessment();
        riskAssessment.setInitFlag(initFlag);
        MatchOdds jc = null;
        if(jcOdd.isPresent()){
            jc = jcOdd.get();
        }
        MatchOdds vl = null;
        if(vlOdd.isPresent()){
            vl = vlOdd.get();
        }
        MatchOdds lb = null;
        if(lbOdd.isPresent()){
            lb = lbOdd.get();
        }

        if(Objects.nonNull(jc) && Objects.nonNull(vl) && Objects.nonNull(lb)){
            BigDecimal mainWinOdds = jc.getMainWinOdds();
            BigDecimal levelOdds = jc.getLevelOdds();
            BigDecimal gustWinOdds = jc.getGustWinOdds();

            BigDecimal vlMain = vl.getMainWinOdds();
            BigDecimal vlLevel = vl.getLevelOdds();
            BigDecimal vlGust = vl.getGustWinOdds();
            BigDecimal lbMain = lb.getMainWinOdds();
            BigDecimal lbLevel = lb.getLevelOdds();
            BigDecimal lbGust =lb.getGustWinOdds();

            String  main = "高";
            if((mainWinOdds.compareTo(vlMain) < 0 && mainWinOdds.compareTo(lbMain) > 0) || mainWinOdds.compareTo(vlMain) > 0 && mainWinOdds.compareTo(lbMain) < 0){
                main = "中";
            }else if(mainWinOdds.compareTo(vlMain) < 0 && mainWinOdds.compareTo(lbMain) < 0){
                main = "低";
            }

            riskAssessment.setMain(main);

            String level = "高";
            if((levelOdds.compareTo(vlLevel) < 0 && levelOdds.compareTo(lbLevel) > 0) || levelOdds.compareTo(vlLevel) > 0 && levelOdds.compareTo(lbLevel) < 0){
                level = "中";
            }else if(levelOdds.compareTo(vlLevel) < 0 && levelOdds.compareTo(lbLevel) < 0){
                level = "低";
            }
            riskAssessment.setLevel(level);

            String gust = "高";
            if((gustWinOdds.compareTo(vlGust) < 0 && gustWinOdds.compareTo(lbGust) > 0) || gustWinOdds.compareTo(vlGust) > 0 && gustWinOdds.compareTo(lbGust) < 0){
                gust = "中";
            }else if(gustWinOdds.compareTo(vlGust) < 0 && gustWinOdds.compareTo(lbGust) < 0){
                gust = "低";
            }
            riskAssessment.setGust(gust);

        }else {
            riskAssessment.setMain("未知");
            riskAssessment.setLevel("未知");
            riskAssessment.setGust("未知");
        }
        return riskAssessment;
    }

    private CompanyVO getCompanyVo(List<Match> matches, String rq) {
        CompanyVO vo = new CompanyVO();

        List<JqCountDto> scoreList =Lists.newArrayList();
        // 比分分布
        Map<String, List<Match>> scoreMap = matches.stream().collect(Collectors.groupingBy(Match::getMatchScore));
        scoreMap.forEach((k,v)->{
            JqCountDto dto =new JqCountDto();
            dto.setDesc(k);
            dto.setNum(v.size());
            scoreList.add(dto);
        });
        vo.setScoreList(scoreList.stream().sorted(Comparator.comparing(JqCountDto::getNum).reversed()).collect(Collectors.toList()));

        // 进球分布
        List<JqCountDto> jqList =Lists.newArrayList();
        Map<String, List<Match>> jqMap = matches.stream().collect(Collectors.groupingBy(g ->{
            return String.valueOf(getJqResultByScore(g.getMatchScore()));
        }));
        jqMap.forEach((k,v)->{
            JqCountDto dto =new JqCountDto();
            dto.setDesc("总进球数"+k);
            dto.setNum(v.size());
            jqList.add(dto);
        });
        vo.setJqList(jqList.stream().sorted(Comparator.comparing(JqCountDto::getNum).reversed()).collect(Collectors.toList()));

        List<JqCountDto> rqList = Lists.newArrayList();
        BigDecimal rqBig = new BigDecimal(rq);
        for (JqCountDto jqCountDto : scoreList) {
            String desc = jqCountDto.getDesc();
            String[] split = desc.split(":");
            BigDecimal mainJq = new BigDecimal(split[0]);
            BigDecimal gustJq = new BigDecimal(split[1]);
            Integer num = jqCountDto.getNum();
            String win = "";
            BigDecimal rqAdd = mainJq.add(rqBig);
            if(rqAdd.compareTo(gustJq) == 0){
                win = "平";
            }else if(rqAdd.compareTo(gustJq) > 0){
                win = "主";
            }else {
                win = "客";
            }
            String finalWin = win;
            Optional<JqCountDto> first = rqList.stream().filter(f -> f.getDesc().equals(finalWin)).findFirst();
            if (first.isPresent()) {
                JqCountDto jqCountDto1 = first.get();
                jqCountDto1.setNum(jqCountDto1.getNum() + num);
            }else {
                JqCountDto jqCountDto1 = new JqCountDto();
                jqCountDto1.setDesc(win);
                jqCountDto1.setNum(num);
                rqList.add(jqCountDto1);
            }
        }
        vo.setRqList(rqList.stream().sorted(Comparator.comparing(JqCountDto::getNum).reversed()).collect(Collectors.toList()));
        return vo;
    }

    private List<Match> getInitMatchList(List<MatchOdds> jcOdds, String currentJqSort,int type) {
        OddsDto main = null;
        OddsDto level = null;
        OddsDto gust = null;
        List<Match> matches = Lists.newArrayList();
        List<Match> filterMatches = Lists.newArrayList();
        for (int i = 1; i <= 10; i++) {
            BigDecimal divide = new BigDecimal(i).divide(BigDecimal.TEN,1, RoundingMode.DOWN);
            Optional<MatchOdds> first = jcOdds.stream().filter(f -> f.getInitFlag().equals(Boolean.TRUE)).findFirst();
            if(first.isPresent()){
                MatchOdds matchOdds = first.get();
                main = OddsRangeUtil.getOddsRange2(matchOdds.getMainWinOdds(),divide);
                level = OddsRangeUtil.getOddsRange2(matchOdds.getLevelOdds(),divide);
                gust = OddsRangeUtil.getOddsRange2(matchOdds.getGustWinOdds(),divide);
                matches   = matchMapper.selectListByInitOdds(main,level,gust,type);
                filterMatches = matches.stream().filter(f -> currentJqSort.equals(getMatchJqSortList(f))).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(filterMatches) && filterMatches.size() > 50){
                    break;
                }
            }else {
                break;
            }
        }

        return filterMatches;
    }

    private List<Match> getMatchList(List<MatchOdds> jcOdds, String currentJqSort,int type) {
        OddsDto main = null;
        OddsDto level = null;
        OddsDto gust = null;
        List<Match> matches = Lists.newArrayList();
        List<Match> filterMatches = Lists.newArrayList();
        for (int i = 1; i <= 10; i++) {
            BigDecimal divide = new BigDecimal(i).divide(BigDecimal.TEN,1, RoundingMode.DOWN);
            main = getMainOdds(jcOdds,divide);
            level = getLevelOdds(jcOdds,divide);
            gust = getGustOdds(jcOdds,divide);
            matches   = matchMapper.selectListByFinalOdds(main,level,gust,type);
            filterMatches = matches.stream().filter(f -> currentJqSort.equals(getMatchJqSortList(f))).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(filterMatches) && filterMatches.size() > 50){
                break;
            }
        }
        return filterMatches;
    }

    private OddsDto getGustOdds(List<MatchOdds> odds, BigDecimal divide) {
        OddsDto dto = new OddsDto();

        MatchOdds first = CollUtil.getFirst(odds);
        MatchOdds last = CollUtil.getLast(odds);

        BigDecimal gustWinOdds = first.getGustWinOdds();
        BigDecimal gustWinOdds1 = last.getGustWinOdds();
        if(gustWinOdds.compareTo(gustWinOdds1) == 0){
            dto.setMin(gustWinOdds.subtract(divide));
            dto.setMax(gustWinOdds.add(divide));
        }else if(gustWinOdds.compareTo(gustWinOdds1) > 0){
            dto.setMin(gustWinOdds1);
            dto.setMax(gustWinOdds);
        }else {
            dto.setMin(gustWinOdds);
            dto.setMax(gustWinOdds1);
        }
        return dto;
    }

    private OddsDto getLevelOdds(List<MatchOdds> odds, BigDecimal divide) {
        OddsDto dto = new OddsDto();

        MatchOdds first = CollUtil.getFirst(odds);
        MatchOdds last = CollUtil.getLast(odds);

        BigDecimal levelOdds = first.getLevelOdds();
        BigDecimal levelOdds1 = last.getLevelOdds();
        if(levelOdds.compareTo(levelOdds1) == 0){
            dto.setMin(levelOdds.subtract(divide));
            dto.setMax(levelOdds.add(divide));
        }else if(levelOdds.compareTo(levelOdds1) > 0){
            dto.setMin(levelOdds1);
            dto.setMax(levelOdds);
        }else {
            dto.setMin(levelOdds);
            dto.setMax(levelOdds1);
        }
        return dto;
    }

    private OddsDto getMainOdds(List<MatchOdds> odds,BigDecimal divide) {
        OddsDto dto = new OddsDto();

        MatchOdds first = CollUtil.getFirst(odds);
        MatchOdds last = CollUtil.getLast(odds);

        BigDecimal mainWinOdds = first.getMainWinOdds();
        BigDecimal mainWinOdds1 = last.getMainWinOdds();
        if(mainWinOdds.compareTo(mainWinOdds1) == 0){
            dto.setMin(mainWinOdds.subtract(divide));
            dto.setMax(mainWinOdds.add(divide));
        }else if(mainWinOdds.compareTo(mainWinOdds1) > 0){
            dto.setMin(mainWinOdds1);
            dto.setMax(mainWinOdds);
        }else {
            dto.setMin(mainWinOdds);
            dto.setMax(mainWinOdds1);
        }
        return dto;
    }

    private Integer getJqResultByScore(String matchScore) {
        List<String> split = StrUtil.split(matchScore, ":");
        Integer a = Integer.valueOf(split.get(0));
        Integer b = Integer.valueOf(split.get(1));
        return a+b;
    }

    private void oddsHandler(int type, List<HistoryMatchOddsChange> changeList,MatchInfoVO matchInfoVO) {
        if(CollUtil.isNotEmpty(changeList)){
            changeList = changeList.stream().sorted(Comparator.comparing(HistoryMatchOddsChange::getTimeAttr)).collect(Collectors.toList());
            HistoryMatchOddsChange first = CollUtil.getFirst(changeList);

            List<MatchOdds> odds = Lists.newArrayList();
            MatchOdds odd= new MatchOdds();
            odd.setMainWinOdds(first.getMainWinOdds());
            odd.setLevelOdds(first.getLevelOdds());
            odd.setGustWinOdds(first.getGustWinOdds());
            odd.setTimeAttr(first.getTimeAttr());
            odd.setTimeText(first.getTimeText());
            odd.setInitFlag(Boolean.TRUE);
            odds.add(odd);
            HistoryMatchOddsChange last = null;
            if (type != 1) {
                List<MatchOdds> jcOdds = matchInfoVO.getBaseInfo().getJcOdds();
                MatchOdds last1 = CollUtil.getLast(jcOdds);
                List<HistoryMatchOddsChange> changeList1 =changeList.stream().filter(f -> {
                    String timeAttr = "2023-" + last1.getTimeAttr() + ":00";
                    String timeAttr1 = "2023-" + f.getTimeAttr() + ":00";
                    LocalDateTime start = LocalDateTime.parse(timeAttr, DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
                    LocalDateTime end = LocalDateTime.parse(timeAttr1, DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
                    return !end.isAfter(start);
                }).collect(Collectors.toList());
                if(CollUtil.isNotEmpty(changeList1)){
                    changeList = changeList1;
                }
            }
            last = CollUtil.getLast(changeList);
            odd= new MatchOdds();
            odd.setMainWinOdds(last.getMainWinOdds());
            odd.setLevelOdds(last.getLevelOdds());
            odd.setGustWinOdds(last.getGustWinOdds());
            odd.setTimeAttr(last.getTimeAttr());
            odd.setTimeText(last.getTimeText());
            odd.setInitFlag(Boolean.FALSE);
            odds.add(odd);
            if(type == 1){
                matchInfoVO.getBaseInfo().setJcOdds(odds);
            }else if(type == 2){
                matchInfoVO.getBaseInfo().setVlOdds(odds);
            }else {
                matchInfoVO.getBaseInfo().setLbOdds(odds);
            }
        }
    }
}
